﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using OpenLS.Spreadsheet.Formats.Biff.OfficeArt;

namespace OpenLS.Spreadsheet.Formats.Biff.Records
{
    internal class MsoDrawingRecord : WorksheetLevelRecord
    {
        internal OfficeArtDgContainer rgChildRec;


        internal override BiffRecordType RecordType
        {
            get { return BiffRecordType.MsoDrawing; }
        }

        private byte[] _buffer;

        public override void ReadWithContinue()
        {
            if (IsContinue)
                return;
            List<byte> _bytes = new List<byte>(_buffer);
            int length;
            using (MemoryStream memoryStream = new MemoryStream(_bytes.ToArray()))
            {
                using (BinaryReader reader = new BinaryReader(memoryStream))
                {
                   OfficeArtRecordHeader header = new OfficeArtRecordHeader();
                    header.Read(reader);
                    length = (int) header.recLen;
                }
            }
            BiffRecord record = this.Next ;
            BiffRecord previousRecord = this;
            var objRecords = new Dictionary<int, ObjRecord>();
            var txORecords = new Dictionary<int, TxORecord>();
            int txoContinue = 0;
            int objContinue = 0;
            while (_bytes.Count < length + OfficeArtRecordHeader.ByteLength)
            {
                Contract.Assert(_bytes.Count < length + OfficeArtRecordHeader.ByteLength);
                Contract.Assert(!(previousRecord is ContinueRecord));
                if (record is ContinueRecord)
                {
                    if (previousRecord is TxORecord)
                    {
                        if (txoContinue < ((TxORecord) previousRecord).FullLength)
                        {
                            txoContinue += ((ContinueRecord) record).Buffer.Length;
                        }
                        else
                        {
                            _bytes.AddRange(((ContinueRecord)record).Buffer);
                        }
                    }
                    else if (previousRecord is ObjRecord)
                    {
                        if (objContinue < 0)
                        {
                            objContinue += ((ContinueRecord)record).Buffer.Length;
                        }
                        else
                        {
                            _bytes.AddRange(((ContinueRecord)record).Buffer);
                        }
                    }
                    else if (previousRecord is MsoDrawingRecord)
                    {
                        _bytes.AddRange(((ContinueRecord)record).Buffer);
                    }
                    else
                    {
                        // Contract.Assert(false);
                    }
                }
                else if (record is MsoDrawingRecord)
                {
                    MsoDrawingRecord drawingRecord = (MsoDrawingRecord)record;
                    _bytes.AddRange(drawingRecord._buffer);
                    drawingRecord.IsContinue = true;
                }
                else if (record is TxORecord)
                {
                    txORecords.Add(_bytes.Count, (TxORecord)record);
                    txoContinue = 0;
                }
                else if (record is ObjRecord)
                {
                    objRecords.Add(_bytes.Count, (ObjRecord) record);
                    objContinue = 0;
                }
                else 
                {
                    Contract.Assert(false);
                }
                if (!(record is ContinueRecord))
                {
                    previousRecord = record;
                }
                record = record.Next;
            }
            while (record is TxORecord || record is ContinueRecord)
            {
                if (record is TxORecord)
                    txORecords.Add(_bytes.Count, (TxORecord) record);
                record = record.Next;
            }
            Contract.Assert((length + OfficeArtRecordHeader.ByteLength == _bytes.Count));
            using (MemoryStream memoryStream = new MemoryStream(_bytes.ToArray()))
            {
                using (BinaryReader reader = new BinaryReader(memoryStream))
                {
                    OfficeArtReadContext context = new OfficeArtReadContext(reader, objRecords, txORecords);

                    rgChildRec = new OfficeArtDgContainer();
                    rgChildRec.Read(context);
                }
            }
        }
        private bool IsContinue;

        public MsoDrawingRecord(byte[] buffer)
        {
            Contract.Requires(buffer != null);
            Contract.Requires(buffer.Length > 0);
            _buffer = buffer;
        }

        public MsoDrawingRecord()
        {
        }

        protected override void ReadContent(BiffReaderContext context, int length)
        {
            _buffer = context.ReadBytes(length);
        }

        internal override void Apply(BiffReaderWorksheetContext context)
        {
            if (IsContinue)
                return;
            foreach (var item in this.rgChildRec.GroupShapes)
            {
                var anchor = item.GetClientAnchorSheet(context);
                if (anchor != null && anchor.Content != null) //\\Content should always be not null
                    context.Worksheet.Anchors.Add(anchor);
            }
        }

        internal override void WriteContent(BiffWriterWorkbookContext context)
        {
            context.Write(_buffer);
        }
    }
}